<?php

namespace App\Http\Controllers\Prize;

use App\App\Services\CsvReader;
use App\Contracts\Repositories\PrizeRepository as PrizeRepositoryContract;
use App\Entities\Prize;
use App\Entities\PrizeRecord;
use App\Events\VoucherCodeImported;
use App\Morefun\Prize\Flow;
use App\Morefun\Prize\PrizeService;
use Illuminate\Container\Container;
use Illuminate\Database\Connection;
use Illuminate\Database\Query\Builder;
use Illuminate\Http\Request;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Arr;
use Ramsey\Uuid\Uuid;
use Symfony\Component\HttpFoundation\File\Exception\UploadException;

class WebApiController
{
    protected $prizes;
    protected $prize;
    protected $prize_id;

    public function __construct(PrizeRepositoryContract $prizes, PrizeService $prize)
    {
        $this->prizes = $prizes;
        $this->prize = $prize;
    }

    public function available(Request $request)
    {
        $perPage = $request->get('per_page', 15);
        $keyword = $request->get('q');
        $prizes = $this->prizes->findAvailableWithPaginate($perPage, $keyword, [
            'id',
            'name',
            'expired_start',
            'expired_end',
            'stock_number',
            'type_code',
            'background_image',
        ]);

        $prizes = $this->prize->fillAvailableNumber($prizes);

        return response()->success($prizes);
    }

    public function importVoucherCode(Request $request, CsvReader $csv)
    {
        try {
            $file = $request->file('codes');
            $this->validate($file);
        } catch (UploadException $exception) {
            return response()->failed($exception->getMessage());
        }

        $prizeId = $request->input('prize_id');

        if (!Uuid::isValid($prizeId)) {
            return response()->failed('prize_id不合法');
        }
        $this->flushCodeToRedis($prizeId);
        /**
         * @var Connection
         */
        $database = $this->database();

        /**
         * @var Builder
         */
        $table = $database->table('voucher_codes');

        $database->beginTransaction();

        try {
            $csv->load($file->path())->skip(1);
            $count = 0;
            $limit = 1000;
            $redis = $this->redis();
            $key = $this->keyOfCodeUniqueInRedis($prizeId);

            foreach ($csv->read() as $item) {
                if ($limit == 0 || !($code = Arr::get($item, '0'))) {
                    break;
                }

                if (!$redis->sismember($key, $code)) {
                    $table->insert(['prize_id' => $prizeId, 'code' => $code]);
                    $redis->sadd($key, $code);
                    ++$count;
                }

                --$limit;
            }

            // 写入库存
            Prize::query()->where('id', $prizeId)->increment('stock_number', $count);
            // 入库库存
            (new Flow())->witch($prizeId)->record(PrizeRecord::ENTRY, $count);
            $redis->del($key);
            event(new VoucherCodeImported($prizeId));
            $database->commit();
        } catch (\Exception $e) {
            $database->rollBack();
            return response()->failed('导入失败，可能是你的码劵里面含有中文或者非法字符');
            //return response()->failed($e->getMessage());
        }

        return response()->success("导入成功{$count}条劵码");
    }

    protected function validate(UploadedFile $file = null)
    {
        if (!$file) {
            throw new UploadException('请上传码劵文件');
        }

        if (!$file->isValid()) {
            throw new UploadException('上传的文件不合法');
        }

        if ($file->getMimeType() !== 'text/plain') {
            throw new UploadException('只能上传csv文件');
        }
    }

    protected function flushCodeToRedis($prizeId)
    {
        $codes = $this->database()->table('voucher_codes')->where('prize_id', $prizeId)->pluck('code');
        $key = $this->keyOfCodeUniqueInRedis($prizeId);
        $redis = $this->redis();

        foreach ($codes as $code) {
            $redis->sadd($key, $code);
        }
    }

    protected function database()
    {
        return Container::getInstance()->make('db');
    }

    protected function redis()
    {
        return Container::getInstance()->make('redis');
    }

    protected function keyOfCodeUniqueInRedis($prizeId)
    {
        return sprintf('__codes:%s', $prizeId);
    }
}
